package com.tanhua.server.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 拦截器  拦截请求  读取缓存中的数据
 */
@Component
public class RedisCacheInterceptor implements HandlerInterceptor {

    private static ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${tanhua.cache.enable}")
    private Boolean enable;

    /*@Autowired
    private UserService userService;*/

    //在业务处理器处理请求之前被调用。预处理，可以进行编码、安全控制、权限校验等处理；
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //token验证
     /*   String token = request.getHeader("Authorization");
        User user = this.userService.queryUserByToken(token);
        if (null == user) {
            response.setStatus(401);
            return false;
        }
        UserThreadLocal.set(user);*/





        if (!enable) {
            //未开启缓存
            return true;
        }

        //判断请求方式：get、post还是其他
        String method = request.getMethod();
        if (!StringUtils.equalsAnyIgnoreCase(method, "GET")) {
            // 非GET的请求不进行缓存处理
            return true;
        }

        // 通过缓存做命中，查询redis，redisKey ?  组成：md5（请求的url + 请求参数）
        String redisKey = createRedisKey(request);
        String data = this.redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isEmpty(data)) {
            // 缓存未命中
            return true;
        }

        // 将data数据进行响应
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        //将结果返回到前端
        response.getWriter().write(data);

     /*   // 支持跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Token");
        response.setHeader("Access-Control-Allow-Credentials", "true");*/

        //直接返回结果
        return false;
    }

    public static String createRedisKey(HttpServletRequest request) throws
            Exception {

        String paramStr = request.getRequestURI();

        //getParameterMap()返回的是一个Map类型的值，该返回值记录着前端（如jsp页面）
        // 所提交请求中的请求参数和请求参数值的映射关系
        //这个返回值有个特别之处——只能读。不像普通的Map类型数据一样可以修改。
        // 这是因为服务器为了实现一定的安全规范，所作的限制。
        // 比如WebLogic，Tomcat，Resin，JBoss等服务器均实现了此规范。
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap.isEmpty()) {
            //请求体的数据只能读取一次，需要进行包装Request进行解决
            paramStr += IOUtils.toString(request.getInputStream(), "UTF-8");
        } else {
            //使用jackon的ObjectMapper的writeValueAsString方法可以把java对象转化成json字符串
            paramStr += mapper.writeValueAsString(request.getParameterMap());
        }

        String authorization = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty((authorization))) {
            paramStr += "_" + authorization;
        }
         //把String字符串进行md5加密
        return "SERVER_DATA_" + DigestUtils.md5Hex(paramStr);
    }
}
